﻿using System;
using System.ComponentModel;
using System.Windows.Media;
using WickedFlame.Core.Extensions;


namespace WickedFlame.Core.Shapes
{
    public delegate void ChangedEventHandler(object sender, EventArgs e);

    public abstract class DrawableShape : DrawingVisual, INotifyPropertyChanged
    {
        public event ChangedEventHandler ShapeSizeChanged;
        public event ChangedEventHandler ShapeMoved;
        public event ChangedEventHandler ShapeChangeEnd;

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        protected void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

        #endregion

        public virtual void Invalidate()
        {
            DrawingContext dc = this.RenderOpen();

            Draw(dc);

            dc.Close();
        }

        /// <summary>
        /// Drwas the shape
        /// </summary>
        /// <param name="drawingContext"></param>
        public abstract void Draw(DrawingContext drawingContext);

        #region Properties

        bool _isSelected = false;
        public virtual bool IsSelected
        {
            get
            {
                return _isSelected;
            }
            set
            {
                if (_isSelecteable)
                    _isSelected = value;
                else
                    _isSelected = false;
            }
        }

        bool _isSelecteable = true;
        public bool IsSelecteable
        {
            get
            {
                return _isSelecteable;
            }
            set
            {
                _isSelecteable = value;
                if (!_isSelecteable)
                {
                    _isSelected = value;
                }
            }
        }

        Brush _stroke = new SolidColorBrush(Colors.Black);
        public Brush Stroke
        {
            get
            {
                return _stroke;
            }
            set
            {
                _stroke = value;

                // set the value to the pen
                Pen.Brush = value;

                Invalidate();
                CallChangedHandler();

				NotifyPropertyChanged("Stroke");
            }
        }

        double _strokeThickness = 1;
        public double StrokeThickness
        {
            get
            {
                return _strokeThickness;
            }
            set
            {
                _strokeThickness = value;

                // set the value to the pen
                Pen.Thickness = value;

                Invalidate();
                CallChangedHandler();

				NotifyPropertyChanged("StrokeThickness");
            }
        }

        Brush _fill = new SolidColorBrush(Colors.Transparent);
        public Brush Fill
        {
            get
            {
                return _fill;
            }
            set
            {
                _fill = value;
                Invalidate();
                CallChangedHandler();

				NotifyPropertyChanged("Fill");
            }
        }

        Pen _pen;
        public Pen Pen
        {
            get
            {
                if (_pen == null)
                {
                    _pen = new Pen(Stroke, StrokeThickness)
                    {
                        StartLineCap = LineCap,
                        EndLineCap = LineCap,
                        LineJoin = LineCap.ToPenLineJoin()
                    };
                }
                return _pen;
            }
        }

        PenLineCap _lineCap = PenLineCap.Round;
        public PenLineCap LineCap
        {
            get
            {
                return _lineCap;
            }
            set
            {
                _lineCap = value;

                // set the value to the pen
                Pen.StartLineCap = value;
                Pen.EndLineCap = value;
                Pen.LineJoin = value.ToPenLineJoin();

                Invalidate();
                CallChangedHandler();

                NotifyPropertyChanged("LineCap");
            }
        }

        

        #endregion

        #region Event callers

        protected void CallMovedHandler()
        {
            if (ShapeMoved != null)
                ShapeMoved(this, new EventArgs());
        }

        protected void CallChangedHandler()
        {
            if (ShapeSizeChanged != null)
                ShapeSizeChanged(this, new EventArgs());
        }

        internal void CallChangeEndHandler()
        {
            if (ShapeChangeEnd != null)
                ShapeChangeEnd(this, new EventArgs());
        }

        #endregion
    }
}
